\subsection{Filtro mblur}

El objetivo de este filtro es producir un efecto de movimiento, obteniendo el valor de cada p\'ixel a partir de una f\'ormula que toma en cuenta p\'ixeles cercanos.

Tanto la implementaci\'on en C como en ASM tiene tres bloques l\'ogicos:

\begin{itemize}
	\item el llenado de las primeras dos filas de la imagen destino con p\'ixeles cuyos componentes tengan valor 0 (es decir un p\'ixel que representa el color negro).
	
	\item el procesamiento del cuerpo de la imagen fuente, que consta de otras tres subpartes:
		\subitem setear en 0 los componentes de las dos primeras columnas, es decir, hacer que los dos primeros p\'ixeles sean de color negro.
		\subitem el procesamienteo de cada uno de los p\'ixeles interiores, de acuerdo a lo definido en el enunciado.
		\subitem setear en 0 los componentes de las dos \'ultimas columnas, es decir, hacer que los dos \'ultimos p\'ixeles sean de color negro.

	\item el llenado de las \'ultimas dos filas de la imagen destino con p\'ixeles cuyos componentes tengan valor 0.
\end{itemize}

\subsubsection{Implementaci\'on en C}

	La primera parte se realiza de forma directa con un doble ciclo anidado que va asignando el valor 0 a cada uno de los bytes de los que consta la fila. Como se sabe que cada p\'ixel est\'a representado por 4 bytes (los componentes RGB y el \textit{alpha}), y se tiene la matriz de p\'ixeles en una variable de tipo unsigned char (*src_matrix), se usa la asignaci\'on con corchetes en cada uno de los $4 \times columnas$ bytes de las primeras dos filas.  
	
Las primeras dos filas deben tener el color negro: simplemente se itera sobre ellas, llen\'andola con el p\'ixel que tiene 0 en cada una de sus componentes.
\\
\begin{codesnippet}
\begin{verbatim}

    Para i = 0 hasta 2; Paso: i++
        Para j = 0 hasta Columnas de la Imagen * 4 (tamx); Paso: j ++

        Escribir en el pixel (0, 0, 0) y alpha 0 en imagen destino 

        Fin Para
    Fin Para
\end{verbatim}
\end{codesnippet}

En el procesamiento del cuerpo de la imagen, se hace un recorrido desde la tercera fila hasta la fila \textit{cantidad de filas $- 1$}. En las primeras dos columnas, se pasa a la imagen destino el p\'ixel de color negro (0, 0, 0). Hasta la columna \textit{cantidad de columnas $- 2$}, se realiza una suma de los componentes correspondientes de los p\'ixeles que forman una diagonal en la imagen, desde la dos filas por encima de la fila que se est\'a recorriendo hasta dos filas por debajo de la que se est\'a recorriendo. Esta suma se la divide por 5, ya que es lo mismo que multiplicarlo por 0.2. 

Por ejemplo, si cada cuadrado de la ret\'icula que se presenta m\'as abajo representara un byte (componente):
\begin{figure}
  \begin{center}
   \includegraphics[scale=0.66]{imagenes/grid.png}
  \end{center}
\end{figure}
y en el recorrido de la fila del centro, se encontrara  el byte que se encuentra marcado como rojo en el centro de la imagen, se tendr\'ia que sumar los valores de los bytes marcados con color y dividirlos por 5.
\\
\\
Las \'ultimas dos columnas de una fila del cuerpo tambi\'en tienen que tener 0 como valor en cada uno de sus componentes.

\begin{codesnippet}
\begin{verbatim}

    Para i = 2 hasta cantidad filas - 1; Paso: i++
        Para j = 0 hasta 8; Paso: j ++
            pasar el valor 0 al byte j
        Fin Para
		
        Para j = 0 hasta 4 * cantidad de columnas - 8; Paso: j++ 
              valor := (src_matrix[i - 2][j - 8] + src_matrix[i - 1][j - 4] +
                       src_matrix[i][j] + src_matrix[i + 1][j + 4] +
                       src_matrix[i + 1][i + 4] + src_matrix[i + 2][j + 8])/5
                       
              Si valor > 255
              	  valor := 255
              FinSi
                            
              dst_matrix[i][j] = valor              
        Fin Para

        Para j = filas - 2 hasta filas; Paso: j ++
            pasar el valor 0 al byte j
        Fin Para

    Fin Para
\end{verbatim}
\end{codesnippet}

Las \'ultimas dos filas deben tener el color negro: simplemente se itera sobre ellas, llen\'andola con el p\'ixel que tiene 0 en cada una de sus componentes.

\begin{codesnippet}
\begin{verbatim}

    Para i = filas - 2 hasta filas; Paso: i++
        Para j = 0 hasta Columnas de la Imagen * 4 (tamx); Paso: j ++

        Escribir en el pixel (0, 0, 0) y alpha 0 en imagen destino 

        Fin Para
    Fin Para
\end{verbatim}
\end{codesnippet}

\subsubsection{Implementaci\'on en ASM}

La implementaci\'on en ASM, como se dijo, sigue la misma l\'ogica, pero realiza gran cantidad de operaciones en paralelo.
Antes de empezar el procesamiento de la imagen, se reserva el registro XMM15 para guardar el valor 5 en punto flotante de precisi\'on simple en cada uno de los dwords. Para ello, se ejecuta el siguiente c\'odigo asm:

\begin{verbatim}
	PXOR XMM15, XMM15				; limpio el registro
	MOV EAX, 5
	MOVD XMM15, EAX					; XMM15 = | 5 | 0 | 0 | 0 |
	MOVUPS XMM14, XMM15				; XMM14 = | 5 | 0 | 0 | 0 | 
	PSLLDQ XMM15, 4					
	PXOR XMM15, XMM14				; XMM15 = | 5 | 5 | 0 | 0 |
	MOVUPS XMM14, XMM15	
	PSLLDQ XMM14, 8
	PXOR XMM15, XMM14				; XMM15 = | 5 | 5 | 5 | 5 |
	CVTDQ2PS XMM15, XMM15			; XMM15 = | 5.0 | 5.0 | 5.0 | 5.0 |

\end{verbatim}
 
La primera parte es similar a C, con la mejora de que se setea el valor 0 en 16 bytes en forma paralela. Para recorrer las dos primeras filas, se usa como contador el registro R12. RSI tiene el puntero al comienzo de la fila que estamos recorriendo en la imagen destino. RBX lo usamos como un offset para ir trasladando los valores del byte 0 al destino. Como en el ejercicio 1, se contempla el caso del borde de la fila, haciendo retroceder el procesamiento para terminar exactamente en el pasaje de los valores a destino de los \'ultimos 16 bytes (y no tocar memoria m\'as all\'a del fin de la fila)

\begin{codesnippet}
\begin{verbatim}

    Mientras R12 != 2
       Mover a RBX, 16
        
       Mientras RBX < la cantidad de columnas
           setear XMM0 en 0 usando PXOR
           pasar XMM0 a [RSI + RBX - 16]
           RBX += 16
       FinMientras
       Pasar los ultimos 16 bytes de la fila
       R12++
    FinMientras

\end{verbatim}
\end{codesnippet}

En el cuerpo de la imagen, se usa ECX como contador para la cantidad de filas y R13d como contador para el recorrido por las columnas, manteniendo en EDX la cantidad de columnas por 4. Se trata nuevamente de un doble ciclo anidado, por filas y columnas. El procesamiento se hace de a 16 bytes (4 p\'ixeles). En cada iteraci\'on realizamos lo siguiente:

\begin{itemize}
	\item en XMM0 se obtienen 16 bytes de la fila que se est\'a recorriendo (llamemosla \textit{f})
	\item en XMM1 se obtienen 16 bytes de la fila $f - 2$ desplazado 2 p\'ixeles (8 bytes) hacia atr\'as con respecto a la columna que se est\'a considerando en esa instancia del recorrido.
	\item en XMM2 se obtienen 16 bytes de la fila $f - 1$ desplazado 1 p\'ixel (4 bytes) hacia atr\'as con respecto a la columna que se est\'a considerando en esa instancia del recorrido.
	\item en XMM3 se obtienen 16 bytes de la fila $f + 1$ desplazado 1 p\'ixel (4 bytes) hacia adelante respecto a la columna que se est\'a considerando en esa instancia del recorrido.
	\item en XMM4 se obtienen 16 bytes de la fila $f + 2$ desplazado 2 p\'ixel (8 bytes) hacia adelante respecto a la columna que se est\'a considerando en esa instancia del recorrido.
\end{itemize}

Esto quiere decir que en cada iteraci\'on se traen de memoria 4 p\'ixeles de 5 columnas para procesar. Como se tienen que hacer operaciones en formatos que ocupan 4 bytes, se realiza en forma secuencial el procesamiento paralelo de los 4 componentes de un p\'ixel en estas 4 columnas. De esta forma se aprovecha toda la informaci\'on que se obtuvo de memoria. As\'i  se guarda la informaci\'on que se trajo en XMM6 a XMM10, se procesan los primeros p\'ixeles de cada fila, luego los segundos p\'ixeles, luego los terceros y finalmente los cuartos. Esto se realiza b\'asicamente con un shift a derecha de manera de que el p\'ixel a considerar se encuentre en los 4 bytes menos significativos y se apliquen los mismas operaciones en cada uno de los 4 casos:

\begin{verbatim}
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	; shifteo 4 bytes la informacion para seguir con el
	; píxel contiguo
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
	PSRLDQ XMM6, 4
	PSRLDQ XMM7, 4
	PSRLDQ XMM8, 4
	PSRLDQ XMM9, 4
	PSRLDQ XMM10, 4
	
	MOVUPS XMM0, XMM6
	MOVUPS XMM1, XMM7
	MOVUPS XMM2, XMM8
	MOVUPS XMM3, XMM9
	MOVUPS XMM4, XMM10
	
	; procesamos los pixeles que quedan en la parte
	; menos significativa de XMM0 a XMM4
\end{verbatim}

Para cada uno de estos p\'ixeles se realizan las siguientes operaciones:

\begin{itemize}
	\item se desempaquetan los primeros 4 bytes para que me queden como enteros de 4 bytes. Por ejemplo, para el caso de los 4 bytes (p\'ixel) de XMM0, se realiz\'o lo siguiente:
\begin{verbatim}	
	PXOR XMM5, XMM5
	PUNPCKLBW XMM0, XMM5
	PUNPCKLWD XMM0, XMM5
\end{verbatim}
	\item se suman los componentes desempaquetados en XMM0 a XMM4 en forma paralela con PADD

	\item se convierte la suma a punto flotante de precisi\'on simple (CVTPS2DQ)

	\item se divide por 5 en forma paralela usando XMM15
	
	\item se convierte nuevamente a enteros y se empaqueta de nuevo para obtener el valor saturado a 255 en bytes
	\begin{verbatim}
    CVTPS2DQ XMM0, XMM0			; en XMM0 esta el resultado de la suma / 5 (suma * 0.2)
    PACKUSDW XMM0, XMM0        
    PACKUSWB XMM0, XMM0
	\end{verbatim}	
		
\end{itemize}

Los resultados de estos valores se guardan en forma contigua en el registro XMM11. Despu\'es de procesar los 4 bytes de las 5 filas, se realiza el pasaje del XMM11 en la imagen destino.

Finalmente, la tercera y \'ultima parte l\'ogica es similar al de las primeras dos filas. Es el pasaje de los p\'ixeles en negro a las \'ultimas dos filas de la imagen destino.

\subsubsection{Experimentos y An\'alisis de resultado}

En el siguiente experimento, se midi\'o el tiempo de ejecuci\'on de mblur 10 veces para la versi\'on en ASM y en C con los distintos flags de optimizaci\'on para im\'agenes de $100 \times 100$, de $200 \times 200$ y de $300 \times 300$. Se extrajeron 4 outliers, los dos de m\'axima duraci\'on y los dos de menos duraci\'on y se obtuvo un promedio y la variaza de los resultados:
\\
\\
    \begin{tabular}{ | l | l | l | l | l | l |}
    \hline
	Dimensi\'on & ASM & -O0 & -01 & -O2 & -O3 \\ \hline
	Promedio 100x100 & 142,20 & 927,95 & 798,31 & 739,289.33 & 897,411.33 \\ \hline
	Promedio 200x200 & 576,45 & 3,712,650.66 & 3,369,822.67 & 2,980,472 & 3,759,900 \\ \hline
	Promedio 300x300 & 1,412,896.67 & 8,333,158 & 7,451,586.67 & 6,761,956.67 & 8,382,437.33 \\ \hline
    \end{tabular}
\\
\\
    \begin{tabular}{ | l | l | l | l | l | l |}
    \hline
	Dimensi\'on & ASM & -O0 & -01 & -O2 & -O3 \\ \hline
	Var 100x100 & 35,921,976.96 & 534,364,174.67 & 66,246,602.67 & 999,262.22 & 656,056,354.22 \\ \hline
	Var 200x200 & 160,301,59 & 8,355,872,488.89 & 4,285,999,288.89 & 2,836,674,885.33 & 9,313,614,581.33 \\ \hline
	Var 300x300 & 961,501,204.22 & 1,781,745,796 & 111,479,944.89 & 3,089,583,084.89 & 4,624,972,334.22 \\ \hline
    \end{tabular}
\\
\\
\begin{figure}[H]
  \begin{center}
   \includegraphics[scale=0.66]{imagenes/grafico4-1.png}
  \end{center}
\end{figure}


\begin{figure}[H]
  \begin{center}
   \includegraphics[scale=0.66]{imagenes/grafico4-2.png}
  \end{center}
\end{figure}

Nuevamente, se observa que la peor optimizaci\'on, como en el ejercicio 1, corresponde a -O3. Por otra parte, la versi\'on en ensamblador es claramente m\'as performante que las implementaciones en C.



